package com.ssfeng.youxia.services;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * Created by liyuhang on 2019-09-14.
 */
@Service
public class RedisService {

    private static final Logger logger = LoggerFactory.getLogger(RedisService.class);


    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private DefaultRedisScript redisScript;


    /***
     *单redis节点分布式失败锁
     * @param lockName 锁标志
     * @param lockTimeout 过期时间
     * @return
     */
    String acquireLockWithTimeout(String lockName,  long lockTimeout) {
        String identifier = UUID.randomUUID().toString();
        String lockKey = "lock:" + lockName;
        boolean flag = redisTemplate.opsForValue().setIfAbsent(lockKey, identifier);
        if (flag) {
            redisTemplate.expire(lockKey, lockTimeout, TimeUnit.MILLISECONDS);
            return identifier;
        }
        return null;
    }


    /***
     * 单redis节点分布式等待锁
     * @param lockName
     * @param acquireTimeout
     * @param lockTimeout
     * @return
     */
    public String acquireLockWithTimeout(String lockName, long acquireTimeout, long lockTimeout) {
        String identifier = UUID.randomUUID().toString();
        String lockKey = "lock:" + lockName;
        long end = System.currentTimeMillis() + acquireTimeout;
        while (System.currentTimeMillis() < end) {
            boolean flag = redisTemplate.opsForValue().setIfAbsent(lockKey, identifier);
            if (flag) {
                redisTemplate.expire(lockKey, lockTimeout, TimeUnit.MILLISECONDS);
                return identifier;
            }
            try {
                Thread.sleep(1);
            }catch(InterruptedException ie){
                Thread.currentThread().interrupt();
            }
        }
        return null;
    }

    /***
     * 释放锁
     * @param lockName
     * @param identifier
     * @return
     */
    public boolean releaseLock(String lockName, String identifier) {
        Long result = (Long) redisTemplate.execute(redisScript, Arrays.asList(lockName,identifier));
        return result == 0 ? true : false;
    }

}
